package com.company.game00;

import cn.hutool.core.util.RandomUtil;

import java.awt.*;
import java.util.LinkedList;
import java.util.List;

import static com.company.game00.MyUtil.*;

public class Tank {
    private static final Image[] heroImages = {
            MyUtil.getImage("/static/p1tankU.gif"),
            MyUtil.getImage("/static/p1tankD.gif"),
            MyUtil.getImage("/static/p1tankL.gif"),
            MyUtil.getImage("/static/p1tankR.gif"),
    };

    private static final Image[] enemyImages = {
            MyUtil.getImage("/static/enemy_u.gif"),
            MyUtil.getImage("/static/enemy_d.gif"),
            MyUtil.getImage("/static/enemy_l.gif"),
            MyUtil.getImage("/static/enemy_r.gif"),
    };

    public static final int DIR_UP = 0;
    public static final int DIR_DOWN = 1;
    public static final int DIR_LEFT = 2;
    public static final int DIR_RIGHT = 3;

    public static final int RADIUS = 30;
    public static final int DEFAULT_SPEED = 5;

    public static final int STATE_STAND = 0;
    public static final int STATE_MOVE = 1;
    public static final int STATE_DIE = 2;

    public static final int DEFAULT_HP = 1000;

    private int x, y;
    private int dir;
    private int state = STATE_STAND;
    private int speed = DEFAULT_SPEED;
    private int hp = DEFAULT_HP;
    private Color color;
    private boolean visible = true;

    private final List<Bullet> bullets = new LinkedList<>();

    public Tank() {
    }

    public Tank(int x, int y, int dir) {
        this.x = x;
        this.y = y;
        this.dir = dir;
        this.color = this instanceof EnemyTank ? Color.GREEN : Color.YELLOW;
    }

    BloodBar bloodBar = new BloodBar();

    public void draw(Graphics g) {
        drawTank(g);
        drawBullets(g);
        bloodBar.draw(g);
        logic();
    }

    private void drawTank(Graphics g) {
        if (this instanceof EnemyTank) {
            EnemyTank enemyTank = (EnemyTank) this;
            g.drawImage(enemyImages[dir], x - RADIUS, y - RADIUS, null);
            enemyTank.ai();
        } else {
            g.drawImage(heroImages[dir], x - RADIUS, y - RADIUS, null);
        }
    }

    private void logic() {
        switch (state) {
            case STATE_STAND:
                break;
            case STATE_MOVE:
                move();
                break;
            case STATE_DIE:
                break;
        }
    }

    private void move() {
        switch (dir) {
            case DIR_UP:
                if (y > RADIUS + MyFrame.TOP)
                    y -= speed;
                break;
            case DIR_DOWN:
                if (y + RADIUS < FRAME_HEIGHT)
                    y += speed;
                break;
            case DIR_LEFT:
                if (x > RADIUS)
                    x -= speed;
                break;
            case DIR_RIGHT:
                if (x + RADIUS < FRAME_WIDTH)
                    x += speed;
                break;
        }
    }

    /**
     * 开火
     */
    public void fire() {
        if (bullets.size() > 5) return;
        int bulletX = x;
        int bulletY = y;
        switch (dir) {
            case DIR_UP:
                bulletY -= RADIUS;
                break;
            case DIR_DOWN:
                bulletY += RADIUS;
                break;
            case DIR_LEFT:
                bulletX -= RADIUS;
                break;
            case DIR_RIGHT:
                bulletX += RADIUS;
                break;
        }
        Bullet bullet = BulletsPool.get(); // 对象池获取子弹对象，并初始坐标等
        bullet.setX(bulletX);
        bullet.setY(bulletY);
        bullet.setDir(dir);
        bullet.setColor(color);
        bullet.setVisible(true);
        bullets.add(bullet);
        if (!(this instanceof EnemyTank)) {
            new Audio("/static/tank_fire.wav").play();
        }
    }

    public void drawBullets(Graphics g) {
        for (int i = 0; i < bullets.size(); i++) {
            Bullet bullet = bullets.get(i);
            if (bullet.isVisible()) {
                bullet.draw(g);
            } else {
                BulletsPool.ret(bullet);
                bullets.remove(bullet);
            }
        }
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public void setDir(int dir) {
        this.dir = dir;
    }

    public void setState(int state) {
        this.state = state;
    }

    public boolean isVisible() {
        return visible;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }

    public List<Bullet> getBullets() {
        return bullets;
    }

    public int getHp() {
        return hp;
    }

    public void setHp(int hp) {
        this.hp = hp;
    }

    /**
     * 血条
     */
    class BloodBar {
        public static final int BAR_LENGTH = 60;
        public static final int BAR_HEIGHT = 5;

        public void draw(Graphics g) {
            g.setColor(Color.YELLOW); // 黄色底色
            g.fillRect(x - RADIUS, y - RADIUS - BAR_HEIGHT * 2, BAR_LENGTH, BAR_HEIGHT);
            g.setColor(Color.RED); // 红色血条
            g.fillRect(x - RADIUS, y - RADIUS - BAR_HEIGHT * 2, hp * BAR_LENGTH / DEFAULT_HP, BAR_HEIGHT);
            g.setColor(Color.WHITE); // 白色边框
            g.drawRect(x - RADIUS, y - RADIUS - BAR_HEIGHT * 2, BAR_LENGTH, BAR_HEIGHT);
        }
    }
}

/**
 * 敌方坦克
 */
class EnemyTank extends Tank {

    private long aiTime;

    public EnemyTank() {
        super();
    }

    public EnemyTank(int x, int y, int dir) {
        super(x, y, dir);
        aiTime = System.currentTimeMillis();
    }

    public void ai() {
        long millis = System.currentTimeMillis();
        if (millis - aiTime > ENEMY_AI_INTERVAL) {
            aiTime = millis;
            setDir(RandomUtil.randomInt(4));
            setState(RandomUtil.randomInt(2));
        }
        if (RandomUtil.randomDouble() < ENEMY_FIRE_PERCENT) {
            fire();
        }
    }
}

/**
 * 子弹
 */
class Bullet {
    public static final int RADIUS = 4;
    public static final int DEFAULT_SPEED = Tank.DEFAULT_SPEED << 1;

    private int x, y;
    private int dir;
    private int atk = 100;
    private int speed = DEFAULT_SPEED;
    private Color color;
    private boolean visible = true;

    public Bullet() {

    }

    public void draw(Graphics g) {
        g.setColor(color);
        g.fillOval(x - RADIUS, y - RADIUS, RADIUS << 1, RADIUS << 1);
        logic();
    }

    public void logic() {
        move();
    }

    private void move() {
        switch (dir) {
            case Tank.DIR_UP:
                y -= speed;
                break;
            case Tank.DIR_DOWN:
                y += speed;
                break;
            case Tank.DIR_LEFT:
                x -= speed;
                break;
            case Tank.DIR_RIGHT:
                x += speed;
                break;
        }
        if (x < 0 || x > FRAME_WIDTH || y < 0 || y > FRAME_HEIGHT) visible = false;
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setDir(int dir) {
        this.dir = dir;
    }

    public int getAtk() {
        return atk;
    }

    public void setAtk(int atk) {
        this.atk = atk;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public boolean isVisible() {
        return visible;
    }

    public void setVisible(boolean visible) {
        this.visible = visible;
    }
}

/**
 * 爆炸
 */
class Boom {
    private static final Image[] booms = new Image[16];

    static {
        for (int i = 0; i < booms.length; i++) {
            booms[i] = MyUtil.getImage("/static/e" + (i + 1) + ".gif");
        }
    }

    private int x;
    private int y;
    private int life = 0;

    public Boom(int x, int y) {
        this.x = x;
        this.y = y;
        new Audio("/static/explode.wav").play();
    }

    public void draw(Graphics g) {
        if (life < booms.length) {
            g.drawImage(booms[life++], x, y, null);
        }
    }

    public int getLife() {
        return life;
    }
}
